#pragma once

#include "Comm.hpp"
#include "Any.hpp"
#include "Buffer.hpp"
#include "Socket.hpp"
#include "EventLoop.hpp"


enum ConnStatu
{
    DISCONNECTED,      // 连接关闭状态 
    CONNECTING,        // 连接建立成功，待处理状态 
    CONNECTED,         // 已连接，各章设置完成，可以通信的状态 
    DISCONNECTING,     // 待关闭状态 
};

class Connection;
using PtrConnection = std::shared_ptr<Connection>;

class Connection : public std::enable_shared_from_this<Connection>
{
private:
    using ConnectedCallback = std::function<void(const PtrConnection&)>;
    using MessageCallback = std::function<void(const PtrConnection&, Buffer*)>;
    using ClosedCallback = std::function<void(const PtrConnection&)>;
    using AnyEventCallback = std::function<void(const PtrConnection&)>;

    // 并非实际的数据发送接口 
    void SendInLoop(Buffer &buf)
    {
        if ((_statu == DISCONNECTED) || (buf.GetSizeOfReadableData() == 0)) return;
        _out_buffer.WriteBuffer(buf);
        if (_channel.IsWriteAbleCtl() == false)
        {
            _channel.EnableWrite();
        }
    }

    // 并非实际的连接关闭操作 
    void ShutdownInLoop()
    {
        _statu = DISCONNECTING;
        if (_in_buffer.GetSizeOfReadableData() > 0)
        {
            if (_message_callback) _message_callback(shared_from_this(), &_in_buffer);
        }
        if (_out_buffer.GetSizeOfReadableData() > 0)
        {
            if (_channel.IsWriteAbleCtl() == false) _channel.EnableWrite();
        }

        if (_out_buffer.GetSizeOfReadableData() == 0)
        {
            Release();
        }
    }

    // 启动非活跃连接释放规则 
    void EnableInactiveReleaseInLoop(int sec)
    {
        // 1、将判断标志置为 true 
        _enable_inactive_release = true;
        // 2、如果当前定时销毁任务已经存在，那就刷新延迟一下即可 
        if (_loop->HasTimer(_conn_id)) return _loop->TimerRefresh(_conn_id);
        // 3、如果不存在定时销毁任务，则新增 
        return _loop->TimerAdd(_conn_id, sec, std::bind(&Connection::Release, this));
    }

    // 取消非活跃连接释放规则 
    void CancleInactiveReleaseInLoop()
    {
        _enable_inactive_release = false;
        if (_loop->HasTimer(_conn_id)) _loop->TimerCancel(_conn_id);
    }

    // 实际的释放接口
    void ReleaseInLoop()
    {
        // 1、修改连接状态，将其置为 DISCONNECTED 
        _statu = DISCONNECTED;
        // 2、移除连接事件监控 
        _channel.Remove();
        // 3、关闭描述符 
        _socket.Close();
        // 4、如果当前定时器队列中还有定时销毁任务，则去取消任务 
        if (_loop->HasTimer(_conn_id)) CancleInactiveReleaseInLoop();
        // 5、关闭回调函数，先调用组件使用者的用户回调，再调用服务器的回调（移除服务器内部管理的连接信息） 
        if (_closed_callback) _closed_callback(shared_from_this());
        if (_server_closed_callback) _server_closed_callback(shared_from_this());
    }

    // 连接获取之后，所处的状态下要进行各种设置 
    // 给 channel 设置事件回调，启动读监控 
    void EstablishedInLoop()
    {
        // 1、修改连接状态 
        assert(_statu == CONNECTING); // 当前的状态一定是上层的半连接状态 
        _statu = CONNECTED;
        // 2、启动读事件监控 
        _channel.EnableRead();
        // 3、调用回调函数 
        if (_connected_callback) _connected_callback(shared_from_this());
    }
    
    void HandleRead()
    {
        // 1、接收 Socket 数据，放到缓冲区 
        char buffer[65536]; // 64 KB
        ssize_t ret = _socket.NonBlockRecv(buffer, (sizeof buffer) - 1);
        if (ret < 0)
        {
            // 出错不能直接关闭 
            return ShutdownInLoop();
        }
        else if (ret == 0) return;
        _in_buffer.Write(buffer, ret);
        // 2、调用 message_callback 进行业务处理 
        if (_in_buffer.GetSizeOfReadableData() > 0)
        {
            return _message_callback(shared_from_this(), &_in_buffer);
        }
    }

    void HandleWrite()
    {
        int len = _out_buffer.GetSizeOfReadableData();
        ssize_t ret = _socket.NonBlockSend(_out_buffer.GetReadPos(), len);
        if (ret < 0)
        {
            // 发送错误就关闭连接 
            if (_in_buffer.GetSizeOfReadableData() > 0)
                _message_callback(shared_from_this(), &_in_buffer);
            return Release(); // 实际的关闭释放操作 
        }
        _out_buffer.MoveReadBackward(ret);

        len = _out_buffer.GetSizeOfReadableData();
        if (len == 0)
        {
            _channel.DisableWrite();
            if (_statu == DISCONNECTING)
            {
                return Release(); // 实际的关闭释放操作 
            }
            return;
        }
    }

    void HandleDisconn()
    {
        if (_in_buffer.GetSizeOfReadableData() > 0)
            _message_callback(shared_from_this(), &_in_buffer);
        return Release();
    }

    void HandleError()
    {
        return HandleDisconn();
    }

    void HandleElseEvent()
    {
        // 1、刷新连接活跃度 --> 延迟定时销毁任务 
        if (_enable_inactive_release == true) _loop->TimerRefresh(_conn_id);
        
        // 2、调用组件使用者的任意事件回调 
        if (_any_event_callback) _any_event_callback(shared_from_this());
    }

    void UpgradeInLoop(
        const Any& context, 
        const ConnectedCallback& conn, 
        const MessageCallback& msg, 
        const ClosedCallback& closed, 
        const AnyEventCallback& any_event)
    {
        _context = context;
        _connected_callback = conn;
        _message_callback = msg;
        _closed_callback = closed;
        _any_event_callback = any_event;
    }

public:
    Connection(uint64_t conn_id, EventLoop* loop, int sockfd)
        : _conn_id(conn_id), 
          _sockfd(sockfd), 
          _socket(_sockfd), 
          _channel(_sockfd), 
          _statu(CONNECTING), 
          _enable_inactive_release(false), 
          _loop(loop)
    {
        _channel.RegisterOperator(
            std::bind(&EventLoop::UpdateEvent, _loop, &_channel), 
            std::bind(&EventLoop::RemoveEvent, _loop, &_channel));
        _channel.SetDisconnCallback(std::bind(&Connection::HandleDisconn, this));
        _channel.SetReadCallback(std::bind(&Connection::HandleRead, this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite, this));
        _channel.SetErrorCallback(std::bind(&Connection::HandleError, this));
        _channel.SetElseCallback(std::bind(&Connection::HandleElseEvent, this));
    }

    int GetFD() { return _sockfd; }

    int GetID() { return _conn_id; }

    bool IsConnected() { return _statu == CONNECTED; }

    void SetContext(const Any& context) { _context = context; }

    Any* GetContext() { return &_context; }

    void SetConnectedCallback(const ConnectedCallback& cb) { _connected_callback = cb; }

    void SetMessageCallback(const MessageCallback& cb) { _message_callback = cb; }

    void SetClosedCallback(const ClosedCallback& cb) { _closed_callback = cb; }

    void SetAnyEventCallback(const AnyEventCallback& cb) { _any_event_callback = cb; }

    void SetSrvClosedCallback(const ClosedCallback& cb) { _server_closed_callback = cb; }

    // 只是将数据放到发送缓冲区，启动写事件监控 
    void Send(const char* data, size_t len)
    {
        Buffer buf;
        buf.Write(data, len);
        LOG(DEBUG, "Connection::SendInLoop\n");
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this, std::move(buf)));
    }

    // 提供给组件使用者的关闭接口，并不实际关闭，还要判断有没有数据待处理 
    void Shutdown()
    {
        LOG(DEBUG, "Connection::ShutdownInLoop\n");
        _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop, this));
    }

    void Release()
    {
        LOG(DEBUG, "Connection::Release\n");
        _loop->PressInPool(std::bind(&Connection::ReleaseInLoop, this));
    }

    // 启动非活跃销毁，并定义非活跃的超时时间，添加定时任务 
    void EnableInactiveRelease(int sec)
    {
        LOG(DEBUG, "Connection::EnableInactiveReleaseInLoop\n");
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, sec));
    }

    // 取消非活跃销毁 
    void CancleInactiveRelease()
    {
        LOG(DEBUG, "Connection::CancleInactiveReleaseInLoop\n");
        _loop->RunInLoop(std::bind(&Connection::CancleInactiveReleaseInLoop, this));
    }

    // 切换协议：重置上下文以及阶段性处理函数 
    void Upgrade(
        const Any& context, 
        const ConnectedCallback& conn, 
        const MessageCallback& msg, 
        const ClosedCallback& closed, 
        const AnyEventCallback& any_event)
    {
        LOG(DEBUG, "Connection::UpgradeInLoop\n");
        _loop->AssertInLoop();
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop, this, context, conn, msg, closed, any_event));
    }

    // 连接建立好后，进行 channel 回调设置，启动读监控 
    void Established()
    {
        LOG(DEBUG, "Connection::EstablishedInLoop\n");
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop, this));
    }

    ~Connection() { LOG(DEBUG, "RELEASE CONNECTION: %d -> %p\n", _sockfd, this); }

private:
    uint64_t _conn_id;               // 连接的唯一 ID，便于连接的管理和查找（也是定时器 ID） 

    int _sockfd;                     // 连接关联的 fd 
    Socket _socket;                  // 连接的套接字操作管理 
    Channel _channel;                // 连接的事件管理 
    ConnStatu _statu;                // 连接的状态类型 
    bool _enable_inactive_release;   // 是否启动非活跃连接销毁，默认为 false 

    Buffer _in_buffer;               // 输入缓冲区 
    Buffer _out_buffer;              // 输出缓冲区 

    Any _context;                    // 请求接收的处理上下文 

    EventLoop* _loop;                // 事件处理 

    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _any_event_callback;
    ClosedCallback _server_closed_callback;
};

